package com.linewell.demo.Signature;

import org.apache.commons.lang.StringUtils;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Title: license-app216
 * @description: 签名工具类
 * @author: hyuhuang@linewell.com
 * @since:2019/3/4
 */
public class SignatureUtil {

//    private static LoggerAdapter logger = LoggerAdapterFactory.getLogger(SignatureUtil.class);

    /**
     * 对数据进行签名认证
     * @param content     入参内容
     * @param privateKey   私钥
     * @return
     */
    public static String rsa256Sign(String content, String privateKey) {
        try
        {
            //根据私钥值来生成私钥对象
            PrivateKey priKey = getPrivateKeyFromPKCS8("RSA", new ByteArrayInputStream(privateKey
                    .getBytes()));
            //签名类型
            Signature signature = Signature.getInstance("SHA256WithRSA");
            //根据私钥初始化签名
            signature.initSign(priKey);
            //更新签名的数据
            signature.update(content.getBytes());
            //生成签名值
            byte[] signed = signature.sign();
            //对生成的签名值进行base64加密
            return new String(Base64.getEncoder().encode(signed));
        }
        catch (Exception e) {
//            logger.error(e.getMessage(),e);
        }
        return null;
    }

    /**
     * 根据私钥获取一个私钥对象
     * @param algorithm
     * @param ins
     * @return
     * @throws Exception
     */
    public static PrivateKey getPrivateKeyFromPKCS8(String algorithm, InputStream ins) throws Exception{
        if ((ins == null) || (StringUtils.isEmpty(algorithm))) {
            return null;
        }
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        //获取私钥
        byte[] encodedKey = IOUtils.inputStreamToByte(ins);
        //对私钥进行base64编码
        encodedKey = Base64.getEncoder().encode(encodedKey);
        //根据解码的私钥生成一个私钥对象
        return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
    }

    public static boolean rsa256CheckContent(String content, String sign, String publicKey) {
        try {
            //公钥对象
            PublicKey pubKey = getPublicKeyFromX509("RSA", new ByteArrayInputStream(publicKey
                    .getBytes()));

            //签名对象
            Signature signature = Signature.getInstance("SHA256WithRSA");
            //初始化验证公钥
            signature.initVerify(pubKey);
            //入参内容
            signature.update(content.getBytes("utf-8"));
            //验证入参内容是否签名
            return signature.verify(Base64.getDecoder().decode(sign.getBytes()));
        } catch (Exception e) {
//            logger.error(e.getMessage(),e);
        }
        return false;
    }

    /**
     * 获取公钥对象
     * @param algorithm
     * @param ins
     * @return
     * @throws Exception
     */
    public static PublicKey getPublicKeyFromX509(String algorithm, InputStream ins)
            throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);

        StringWriter writer = new StringWriter();

        IOUtils.io(new InputStreamReader(ins), writer);
        //获取公钥信息
        byte[] encodedKey = writer.toString().getBytes();
        //对公钥进行解密
        encodedKey = Base64.getDecoder().decode(encodedKey);
        //生成公钥对象
        return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
    }

    /**
     * 对入参排序后验证签名
     * @param map 入参的值
     * @param sign 签名值
     * @param pubKey  公钥
     * @return
     */
    public static boolean verify(Map<String,String> map, String sign, String pubKey) {
        String content = getContent(map);
        return rsa256CheckContent(content, sign, pubKey);
    }

    /**
     * 根据map 拼接key=value&key=value值，若value值为空则不填写过滤
     * 按照排序规则
     * @param map
     * @return
     */
    public static String getContent(Map<String,String> map){
        //拼接的content
        StringBuffer content = new StringBuffer();
        List<String> keys = new ArrayList(map.keySet());
        //排序
        Collections.sort(keys);
        AtomicInteger index = new AtomicInteger();
        keys.forEach(key ->{
            String value = map.get(key);
            if (!org.springframework.util.StringUtils.isEmpty(value)){
                content.append((index.get() == 0 ? "" : "&") + key + "=" + value);
                index.getAndIncrement();
            }
        });

        return content.toString();
    }

    public static void main(String[] args) {

    }
}
